'/
' MOTEP - Massive Online Text Environment Project
' --------------------------------------------------------------------------------
' MOTEP Master Server
' 
' Master.bmx
' 
' (c) Anton Berlin. All Rights Reserved.
'/

' The master object. This is where everything happens. Only one instance
' of this object is possible.
type TMaster
	global instances:int = 0
	
	field m_stopEvent:byte = false
	field m_initiated:byte = false
	field m_pveRealmList:TList = new TList
	field m_pvpRealmList:TList = new TList
	
	' Initialize the master.
	method Initialize:byte()
		if (instances > 0) return 0
		instances:+1
		m_initiated = true
		return 1
	end method
	
	' Main method - this gets executed every frame.
	method Run()
		if (m_initiated) then
			' Receive the next packet.
			local packet:TRKPacket = masterPeer.Receive()
			if (packet) then
				local data:string = string.FromCString(packet.GetData())
				local msgType:int = packet.GetPacketIdentifier()
				local senderAddr:TRKSystemAddress = packet.GetSystemAddress()
				local senderPort:string = senderAddr.GetPort()
				local senderIndex:int = masterPeer.GetIndexFromSystemAddress(packet.GetSystemAddress())
				
				select (msgType)
					case ID_NEW_INCOMING_CONNECTION
						if (senderPort = PVE_SERVER_PORT) then
							write("PVE Server " + senderIndex + " connected from " + senderAddr.ToString() + ".")
							ListAddLast(m_pveRealmList, senderAddr)
						else if (senderPort = PVP_SERVER_PORT) then
							write("PVP Server " + senderIndex + " connected from " + senderAddr.ToString() + ".")
							ListAddLast(m_pvpRealmList, senderAddr)
						else
							write("Client " + senderIndex + " connected from " + senderAddr.ToString() + ".")
						end if
					case ID_DISCONNECTION_NOTIFICATION
						if (senderPort = PVE_SERVER_PORT) then
							write("PVE Server " + senderIndex + " disconnected.")
							ListRemove(m_pveRealmList, senderAddr)
						else if (senderPort = PVP_SERVER_PORT) then
							write("PVP Server " + senderIndex + " disconnected.")
							ListRemove(m_pvpRealmList, senderAddr)
						else
							write("Client " + senderIndex + " disconnected.")
						end if
					case ID_CONNECTION_LOST
						if (senderPort = PVE_SERVER_PORT) then
							write("PVE Server " + senderIndex + " lost the connection.")
							ListRemove(m_pveRealmList, senderAddr)
						else if (senderPort = PVP_SERVER_PORT) then
							write("PVP Server " + senderIndex + " lost the connection.")
							ListRemove(m_pvpRealmList, senderAddr)
						else
							write("Client " + senderIndex + " lost the connection.")
						end if
					case ID_MODIFIED_PACKET
						write("WARNING: Received modified packet from " + senderAddr.ToString() + "!")
						masterPeer.CloseConnection(senderAddr, 1)
						write("Connection kicked.")
					default
						local kind:string = str.word(0, data)
						select (kind)
							case ID_COMMAND
							case ID_INFO
								local infoType:string = str.word(1, data)
								local infoData:string
								
								for local i:int = 2 until str.words(data)
									if (infoData) then
										infoData = infoData + " " + str.word(i, data)
									else
										infoData = str.word(i, data)
									end if
								next
								
								select infoType
									case INFO_SERVER_NAME
										' Treat this later
								end select
							case ID_QUERY
								local query:string = str.word(1, data)
								local args:string
								
								for local i:int = 2 until str.words(data)
									if (args) then
										args = args + " " + str.word(i, data)
									else
										args = str.word(i, data)
									end if
								next
								
								select (query)
									case QUERY_LOGIN_TO_ACCOUNT
										local foundName:byte = false
										local passwordCorrect:byte = false
										local banned:byte = false
										local un:string = arg(args, 1), up:string = arg(args, 2)
										
										for local f:TTField = eachin AccountDatabase.AccessTable("accounts").m_fields
											if (un = f.m_name) then
												foundName = true
												if (up = f.AccessEntry("password").m_stringvalue) then
													passwordCorrect = true
													banned = f.AccessEntry("banned").m_boolvalue
													exit
												end if
											end if
										next
										
										if (foundName) then
											if (passwordCorrect) then
												if (not banned) then
													write("Client " + senderIndex + " logged in to account ~q" + un + "~q.")
													sendMessageToPeer(masterPeer, ID_ANSWER + " " + ANSWER_LOGIN_SUCCESSFUL, 0, senderAddr)
												else
													sendMessageToPeer(masterPeer, ID_ANSWER + " " + ANSWER_ACCOUNT_BANNED, 0, senderAddr)
												end if
											else
												sendMessageToPeer(masterPeer, ID_ANSWER + " " + ANSWER_INVALID_ACCOUNTPASS, 0, senderAddr)
											end if
										else
											sendMessageToPeer(masterPeer, ID_ANSWER + " " + ANSWER_INVALID_ACCOUNTNAME, 0, senderAddr)
										end if
									case QUERY_PVE_REALM_LIST
										Print("Sending PVE Realmlist to " + senderAddr.ToString() + ".")
										sendMessageToPeer(masterPeer, ID_LISTSTART + " " + LIST_PVE_REALM_LIST, 0, senderAddr)
										for local s:TRKSystemAddress  = eachin m_pveRealmList
											sendMessageToPeer(masterPeer, ID_LISTDATA + " " + LIST_PVE_REALM_LIST + " " + s.ToString(), 0, senderAddr)
										next
										sendMessageToPeer(masterPeer, ID_LISTEND + " " + LIST_PVE_REALM_LIST, 0, senderAddr)
									case QUERY_PVP_REALM_LIST
										Print("Sending PVP Realmlist to " + senderAddr.ToString() + ".")
										sendMessageToPeer(masterPeer, ID_LISTSTART + " " + LIST_PVP_REALM_LIST, 0, senderAddr)
										for local s:TRKSystemAddress  = eachin m_pvpRealmList
											sendMessageToPeer(masterPeer, ID_LISTDATA + " " + LIST_PVP_REALM_LIST + " " + s.ToString(), 0, senderAddr)
										next
										sendMessageToPeer(masterPeer, ID_LISTEND + " " + LIST_PVP_REALM_LIST, 0, senderAddr)
								end select
						end select
				end select
				
				masterPeer.DeallocatePacket(packet)
			end if
		end if
	end method
end type



' Extract a specific argument from a message.
function arg:string(args:string, a:int)
	if (a < 1) return null
	return str.word(a - 1, args)
end function
